package com.luke.exercise.classloader;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashMap;
import java.util.Map;

import org.apache.tools.ant.taskdefs.condition.IsLastModified;

public class HotSwapURLClassLoader extends URLClassLoader {

    public static Map<String,Long> cacheLastModifyTimeMap = new HashMap<String, Long>();
    
    public static String projectClassPath = "D:/lusen/git/play/target/classes";
    
    public static String packagePath = "com.luke.classloader";
    
    private static HotSwapURLClassLoader hc = new HotSwapURLClassLoader();
    
    public HotSwapURLClassLoader() {
        super(getMyURLs());
        // TODO Auto-generated constructor stub
    }
    
    public static URL[] getMyURLs() {
        URL url = null;
        try {
            url = new File(projectClassPath).toURI().toURL();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return new URL[] {url};
    }
    
    public static HotSwapURLClassLoader getClassLoader() {
        return hc;
    }
    
    protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
        Class clazz = null;
        clazz = findLoadedClass(name);
        if(clazz != null) {
            if(resolve) {
                resolveClass(clazz);
            }
            if(isModify(name)) {
                hc = new HotSwapURLClassLoader();
                clazz = customLoad(name, hc);
            }
            return clazz;
        }
        if(name.startsWith("java.")) {
            ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
            clazz = systemLoader.loadClass(name);
            if(clazz != null) {
                if(resolve) {
                    resolveClass(clazz);
                }
                return clazz;
            }
        }
        return customLoad(name,this);
    }
    
    public Class load(String name) throws Exception{
        return loadClass(name);
    }
    
    public Class customLoad(String name, ClassLoader loader) throws ClassNotFoundException {
        return customLoad(name, false,loader);
    }
    
    public Class customLoad(String name, boolean resolve, ClassLoader loader) throws ClassNotFoundException {
        Class clazz = ((HotSwapURLClassLoader)loader).findClass(name);
        if(resolve) {
            ((HotSwapURLClassLoader)loader).resolveClass(clazz);
        }
        long lastModifyTime = getClassLastModifyTime(name);
        cacheLastModifyTimeMap.put(name, lastModifyTime);
        return clazz;
    }

    
    private boolean isModify(String name) {
        long lastmodify = getClassLastModifyTime(name);
        long previousModifyTime = cacheLastModifyTimeMap.get(name);
        if(lastmodify > previousModifyTime) {
            return true;
        }
        return false;
    }
    
    private long getClassLastModifyTime(String name) {
        String path = getClassCompletePath(name);
        File file = new File(path);
        if(!file.exists()) {
            throw new RuntimeException(new FileNotFoundException(name));
        }
        return file.lastModified();
    }
    
    private String getClassCompletePath(String name) {
        String simpleName = name.substring(name.lastIndexOf(".")+1);
        return projectClassPath + packagePath + simpleName + ".class";
    }
}
